
// version implementant gini

import ij.ImagePlus;
import ij.plugin.PlugIn;
import ij.process.ColorProcessor;
import ij.process.ImageProcessor;


import java.awt.Color;


import java.awt.Font;

import java.awt.Polygon;
import java.io.PrintStream;

import java.util.Locale;
import java.util.Random; 



import pluginUtils.Circle;
import pluginUtils.CircleArrangement;
import pluginUtils.Complexe; 
import pluginUtils.DoyleCircle;
import pluginUtils.MobiusTransform;

import pluginUtils.PackCircle;


public class CardioidDrawing extends ImagePlus implements PlugIn{
	{Locale.setDefault(Locale.US); }
	
	private int subdiv; 
	private ImageProcessor primeIP; 
	private int X=2000,Y=2000; // image size
	
	private PrintStream output,blenderOutput;
	private double xShift=0; 
	private double zShift=0; 
	
	static double alpha=0.7; 
	static double beta=0.06; 
	//static double suite=1.0/512-3.0/128+1.0/16;
	static double suite=(beta*beta*beta)-3*beta*beta/2.0+beta/2.0; 
	static double a=alpha/suite; 
	static double b=-3.0*a/2; 
	static double c=a/2.0; 
	
	public static double compute(double x){
		return a*x*x*x+b*x*x+c*x; 
	}

	private Random generator=new Random(); // One always needs some randomness
	
	// For the scaling of the image
	private double x0=0,x1=1,y0=0,y1=1;
	private double acoef,ccoef,vcoef,wcoef; 
	
	private String[] palette={"Yellow","Red","Blue","Green","White","NavyBlue","Turquoise","Orange"};
	private Color[] palette1={Color.YELLOW,Color.RED,Color.BLUE,Color.GREEN,Color.MAGENTA,Color.ORANGE};
	public void setCoefs(){
		acoef=X/(x1-x0); 
		vcoef=Y/(y1-y0); 
		ccoef=-acoef*x0; 
		wcoef=-vcoef*y0; 
	}
	 
	
	
	public void setBounds(double xl,double xu,double yl,double yu){
		x0=xl; 
		x1=xu;
		y0=yl;
		y1=yu; 
	}
	
	private void drawCircle(PackCircle c){
		//if(intersect(c))return; 
		
		//if(c.getRadius()<0.1) return; 
		int intX=(int)(c.getX()*acoef+ccoef);
		int intY=(int)(c.getY()*vcoef+wcoef);
		int intRx=(int)(c.getRadius()*acoef);
		int intRy=(int)(c.getRadius()*vcoef);
		int rank=((int)(c.getCouleur()*60))%6; 
	
			
			double Xs=c.getX(); 
			double Ys=c.getY(); 
			double rapp=Xs*Xs+Ys*Ys+1; 
			double u=Xs/rapp; 
			double v=Ys/rapp; 
			double w=(Xs*Xs+Ys*Ys)/rapp;
			
			double Xsr=c.getX(); 
			double Ysr=c.getY()+c.getRadius(); 
			double rappr=Xsr*Xsr+Ysr*Ysr+1; 
			double ur=Xsr/rappr; 
			double vr=Ysr/rappr; 
			double wr=(Xsr*Xsr+Ysr*Ysr)/rappr;
		
			double nrad=(u-ur)*(u-ur)+(v-vr)*(v-vr)+(w-wr)*(w-wr);
			//nrad=Math.sqrt(nrad)*1.414; 
			
			String s="sphere{<"+u+","+v+","+w+">,";
			
			
			s+=nrad; 
			s+=" texture{Texture"+rank+"} finish{Finish"+rank+"}}"; 
			output.println(s);
		
	}
		
	
	private void drawColoredCircle(PackCircle c){
		double xCenter=c.getX(); 
		double yCenter=c.getY(); 
		//if(c.getRadius()<0.001) return ; 
		
		int intX=(int)((xCenter-xShift)*acoef+ccoef);
		int intY=(int)((yCenter-zShift)*vcoef+wcoef);
		int intRx=(int)(c.getRadius()*acoef);
		int intRy=(int)(c.getRadius()*vcoef);
		
		
		primeIP.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
		
		/*
		primeIP.moveTo(intX,intY); 
		primeIP.drawString(c.getMyOrder()+"");
		*/
		
		String s="sphere{<"+xCenter+",0,"+yCenter+">,";
		s+=c.getRadius(); 
		s+=" texture{pigment{color White}} finish{reflection 0.2}}"; 
		System.out.println(s); 
		output.println(s);
	
	}
	
	private void drawCircle(Circle c,double rot,int i){
		double xCenter=c.getCenter().getReal(); 
		double yCenter=c.getCenter().getIm(); 
		//if(c.getRadius()<0.001) return ; 
		
		int intX=(int)((xCenter-xShift)*acoef+ccoef);
		int intY=(int)((yCenter-zShift)*vcoef+wcoef);
		int intRx=(int)(c.getRadius()*acoef);
		int intRy=(int)(c.getRadius()*vcoef);
		
		
		primeIP.drawOval(intX-intRx,intY-intRy,intRx*2,intRy*2);
		
		/*
		primeIP.moveTo(intX,intY); 
		primeIP.drawString(c.getMyOrder()+"");
		*/
		
		String s="torus{"+c.getRadius()+",InternRad texture{T0} finish{F0}\n";
		s+=" rotate "+rot+"*90*k*myVal("+rot+").x*x ";  
		//s+=" rotate "+rot+"*180/pi*k2*z ";  
		s+="translate <"+c.getCenter().getReal()+",0,"+c.getCenter().getIm()+">}\n"; 
		//s+="torus{"+c.getRadius()+",InternRad2 texture{T1} finish{F1}\n";
		//s+=" rotate "+rot+"*90/pi*k*x  rotate 180*z ";  
		//s+="translate <"+c.getCenter().getReal()+",0,"+c.getCenter().getIm()+">}"; 
		System.out.println(s); 
		output.println(s);
		blenderOutput.println(c.getRadius()+" "+c.getCenter().getReal()+" "+c.getCenter().getIm()+" "+rot+" "+(i%8)*32+" "+(i%4)*64+" "+(i%2)*128); 
	
	}
	
	private void drawPoint(Complexe c){
		double xCenter=c.getReal(); 
		double yCenter=c.getIm(); 
		int intX=(int)(xCenter*acoef+ccoef);
		int intY=(int)(yCenter*vcoef+wcoef);
		primeIP.fillOval(intX-10,intY-10,20,20);
	}
	
	
	
	
	
	private void drawLine(double xd,double yd,double xf,double yf){
		int XD=(int)(xd*acoef+ccoef); 
		int YD=(int)(yd*vcoef+wcoef); 
		int XF=(int)(xf*acoef+ccoef); 
		int YF=(int)(yf*vcoef+wcoef);
		primeIP.drawLine(XD,YD,XF,YF); 
	}
	
	
		
	
	
	
	
	public void run(String arg) {
		primeIP = new ColorProcessor(X,Y);
		
		
		double limit=5; 
	
		setBounds(-limit,limit,-limit,limit); 
		setCoefs(); 
		
		
		
		
		
		
		Polygon background=new Polygon(new int[]{0,0,X,Y},new int[]{0,X,Y,0},4);
		primeIP.setColor(Color.WHITE);
		
		primeIP.fillPolygon(background);
		
		
		primeIP.setFont(new Font(null,Font.ITALIC,60));
		primeIP.setColor(Color.BLACK);
		primeIP.setLineWidth(3); 

		try{ 
			output=new PrintStream("C:/users/francesco/pictures/povray/cardioid.txt");
			blenderOutput=new PrintStream("F:/Povray/cardioidBlender.txt"); 
			//output=new PrintStream("C:/users/decomite/pictures/povray/cardioid.txt");
			//blenderOutput=new PrintStream("C:/users/decomite/pictures/povray/cardioidBlender.txt"); 
		} 
		catch(Exception e){System.exit(0); }
		
		setProcessor("Verifying", primeIP);
		
		//drawLine(x0,0,x1,0);
		//drawLine(0,y0,0,y1);
		
		//drawCircle(new Circle(Complexe.ZERO,1));
		//  pitch en (1,0)

		subdiv=100;
		int j; 
		int signe=1; 
		double coef=10.0;

		for(int i=0;i<subdiv;i++){
			Complexe z=Complexe.createComplexeFromPolar(1,i*2*Math.PI/subdiv);
			Complexe zz=Complexe.mul(z, z); 
			j=2*i; 
			
			if(i<=subdiv/2) {
				j=i; 
				signe=1;
				} 
			else {
				j=(subdiv-i);
				signe=-1;
				} 
				
		//	drawCircle(new Circle(z,Complexe.distance(z,Complexe.UN)),signe*Math.PI*Math.pow((j+0.0)/subdiv,1.0/3));
			double coco=(i+0.0)/subdiv; 
			//coco=4*coco*coco-4*coco+1; 
			//coco=coco*coco;
			
			if(Complexe.distance(z,Complexe.UN)!=0){

			drawCircle(new Circle(z,Complexe.distance(z,Complexe.UN)),-signe*compute(coco)*0.3*Math.PI,i);

			//double x2=((j-0.5)/subdiv)*((j-0.5)/subdiv);
			//drawCircle(new Circle(z,Complexe.distance(z,Complexe.UN)),3*x2*signe*Math.PI,0);
			}
		}
		
		show();
		System.out.println("done "); 
		for(int i=0;i<=100;i++)
			System.out.println((i/100.0+" "+compute(i/100.0))); 
		
	}	
}
	